﻿/// <reference path="jquery-2.0.3.js" />
/// <reference path="LiberUI.Base.js" />
/// <reference path="LiberUI.Controller.js" />

function Action() {
    var instance = this;
    instance.evHandlers = [];
    return this;
};
Action.prototype.Fire = function (event,data) {
    var ev = new jQuery.Event(event, data);
    if (this.evHandlers[event]) {
        ev.target = this;
        for (var i = 0; i < this.evHandlers[event].length; i++) {
            var f = this.evHandlers[event][i];
            if (f) {
                f.call(this, ev);
            }
            if (ev.isPropagationStopped && ev.isPropagationStopped == true) {
                break;
            }
        }
    }
    return ev;
};
Action.prototype.on = function (event, fn) {
    if (ObjHelper.IsEmpty(event) || !ObjHelper.IsFunc(fn)) {
        return this;
    }
    if (!this.evHandlers[event]) {
        this.evHandlers[event] = [];
    }
    this.evHandlers[event].push(fn);
    return this;
};
Action.prototype.off = function (event, fn) {
    if (ObjHelper.IsEmpty(event) || !ObjHelper.IsFunc(fn)) {
        return this;
    }
    var hs = this.evHandlers[event];
    if (hs) {
        for (var i = 0; i < hs.length; i++) {
            if (hs[i] === fn) {
                hs[i] = undefined;
                hs.splice(i, 1);
                i--;
            }
        }
        if (hs.length == 0) {
            this.evHandlers[event] = undefined;
        }
    }
    return this;
};

//#region 输入验证框架
function Validater(_opt) {
	/// <summary>
	/// 创建一个输入验证器负责为一组输入元素或控件提供前端合法性验证
	/// </summary>
	/// <returns type="Validater">一个输入验证器</returns>
    var instance = this;
    this.Option = $.extend({}, ValidaterOption, _opt);
    this.Targets = [];
    instance.lastErrElm = null;
    instance.firstErrElm = null;

    this.IsDisposed = false;
    this.IsDisabled = false;

    function checkOnBlur(ev) {
        var id = this.ID();
        var ln = instance.Targets.length;
        var item = null;
        for (var i = 0; i < ln; i++) {
            if (id == instance.Targets[i].id) {
                item = instance.Targets[i];
                break;
            }
        }
        if (item == null) {
            console.log('没有为指定的元素设置检查规则');
            return instance;
        }
        if(!check(item)&&!instance.Option.BlurOnError){
            instance.lastErrElm = item.elm.focus();
            instance.lastErrElm.on("blur", forceFocus);
        }
        else if(instance.lastErrElm){
            instance.lastErrElm.off("blur", forceFocus);
            instance.lastErrElm = null;
        }
    }

    function forceFocus(ev) {
        if (instance.lastErrElm) {
            instance.lastErrElm.focus();
        }
    };

    function check(_item) {
        if (instance.IsDisposed===true||instance.IsDisabled===true) {
            return true;
        }
        var allPass = true;
        var ln = _item.rules.length;
        if (instance.Option.CheckAllRules) {
            //循环执行每条规则,并立刻显示每一个错误或成功的提示
            for (var i = 0; i < ln; i++) {
                var r = _item.rules[i].rule(_item);
                allPass = allPass & r;
                if (r === false) {
                    instance.Option.OnError(_item, _item.rules[i].errInfo);
                }
                else {
                    instance.Option.OnPass(_item, _item.rules[i].passInfo);
                }
            }
            return allPass;
        }
        else {
            //循环执行每条规则直到某一个规则未通过
            for (var i = 0; i < ln; i++) {
                var r = _item.rules[i].rule(_item);
                if (!r) {
                    instance.Option.OnError(_item, _item.rules[i].errInfo);
                    return false;
                }
                else {
                    instance.Option.OnPass(_item, _item.rules[i].passInfo);
                }
            }
            return true;
        }
    }

    function add(_editor, _rule, _passInfo, _errInfo) {
        var ln = instance.Targets.length;
        var item = null;
        var id = _editor.ID();
        for (var i = 0; i < ln; i++) {
            if (id === instance.Targets[i].id) {
                item = instance.Targets[i];
                break;
            }
        }
        if (item == null) {
            item = {
                id: id,
                elm:_editor,
                rules: []
            };
            if (instance.Option.CheckOnBlur === true) {
                _editor.on('blur', checkOnBlur);
            }
            instance.Targets.push(item);
        }

        //如果规则已经存在，更新规则的相关提示信息
        for (var r = 0; r < item.rules.length; r++) {
            if (item.rules[r].rule == _rule) {
                item.rules[r].passInfo = _passInfo;
                item.rules[r].errInfo = _errInfo;
                return;
            }
        }

        //否则新增一个检查规则
        item.rules.push({
            rule: _rule,
            passInfo: _passInfo,
            errInfo:_errInfo
        })
    }

    this.Check = function () {
        this.Enable();
        var ln = this.Targets.length;
        for (var i =0;i< this.Targets.length;i++) {
            if (!check(this.Targets[i])) {
                if (!this.Option.BlurOnError) {
                    instance.lastErrElm = this.Targets[i].elm.on("blur", forceFocus);
                }
                if (!instance.firstErrElm) {
                    instance.firstErrElm = this.Targets[i].elm;
                }
                instance.firstErrElm.focus();
                return false;
            }
        }
        if (instance.lastErrElm) {
            instance.lastErrElm.off("blur", forceFocus);
            instance.lastErrElm = null;
        }
        instance.firstErrElm = null;
        return true;
    }

    this.FirstErr = function () {
        //获取第一个未检查通过的目标元素
        return instance.firstErrElm;
    };

    this.Reset = function () {
        for (var i = 0; i < instance.Targets.length; i++) {
            instance.Targets[i].elm.removeClass("error");
            if (instance.Targets[i].Bubble) {
                instance.Targets[i].Bubble.hide();
                instance.Targets[i].Bubble.dispose();
                instance.Targets[i].Bubble = null;
            }
        }
        if (instance.lastErrElm) {
            instance.lastErrElm.off("blur", forceFocus);
            instance.lastErrElm = null;
        }
        return this;
    };

    this.Disable = function () {
        instance.IsDisabled = true;
        return this;
    };

    this.Enable = function () {
        instance.IsDisabled = false;
        return this;
    };

    this.NoEmpty = function (_editor, _passInfo, _errInfo) {
        /// <summary>
        /// 非空值
        /// </summary>
        /// <param name="_editor" type="JQuery DOM或Controller"></param>
        /// <param name="_passInfo">验证通过时要显示的提示信息</param>
        /// <param name="_errInfo">验证不通过时要显示的提示信息</param>
        if (ObjHelper.IsElement(_editor) || _editor instanceof Controller) {
            add(_editor, ValidateRule.NoEmpty, ObjHelper.IsEmpty(_passInfo) ? "" : _passInfo, ObjHelper.IsEmpty(_errInfo) ? "您是否忘记了填写内容？" : _errInfo);
        }
        return this;
    };
    this.Later = function (_editor, _dateTime, _passInfo, _errInfo) {
        /// <summary>
        /// 必须晚于某个时间
        /// </summary>
        /// <param name="_editor"></param>
        /// <param name="_dateTime"></param>
        /// <param name="_passInfo"></param>
        /// <param name="_errInfo"></param>
    };
    this.IsDate = function (_editor, _passInfo, _errInfo) {
        /// <summary>
        /// 必须是一个日期值
        /// </summary>
        /// <param name="_editor"></param>
        /// <param name="_passInfo"></param>
        /// <param name="_errInfo"></param>
        if (ObjHelper.IsElement(_editor) || _editor instanceof Controller) {
            add(_editor, ValidateRule.IsDate, ObjHelper.IsEmpty(_passInfo) ? "" : _passInfo, ObjHelper.IsEmpty(_errInfo) ? "您是否忘记了填写内容？" : _errInfo);
        }
        return this;
    };

    this.dispose = function () {
        if (this.IsDisposed) {
            return;
        }
        this.IsDisposed = true;
        for (var i = this.Targets.length - 1; i >= 0;i--) {
            this.Targets[i].elm.off('blur', checkOnBlur);
        }
        if (instance.lastErrElm) {
            instance.lastErrElm.off("blur", forceFocus);
            instance.lastErrElm = null;
        }
        this.Targets = [];
        instance = null;
    }

    return this;
}
var ValidaterOption={
    ErrorStyle: 'error', //出现错误时将被附加到所验证的输入控件的样式
    OnPass: function (item, rtnInfo) {
        item.elm.removeClass('error');
        if (item.Bubble) {
            item.Bubble.hide();
            item.Bubble.dispose();
            item.Bubble = null;
        }
    }, //验证通过后的全局回调方法
    OnError: function (item, rtnInfo) {
        item.elm.addClass('error');
        if (!item.Bubble) {
            item.Bubble = new Bubble().ExStyle('Error');
        }
        item.Bubble.Attach(item.elm).Content(rtnInfo).show();
    },  //验证失败后的全局回调方法
    CheckAllRules: false,  //当某一条规则验证失败时，是否继续验证其他的规则，默认不继续
    CheckOnBlur:true,
    BlurOnError:true  //验证失败时是否允许继续移动焦点
}

var ValidateRule = {
    NoEmpty: function (_item) {
        var v = _item.elm.val();
        if (!ObjHelper.IsEmpty(v)) {
            return true;
        }
        else if (ObjHelper.IsFunc(_item.elm.text)) {
            return !ObjHelper.IsEmpty(_item.elm.text());
        }
        else {
            return false;
        }
    },
    IsDate: function (_item) {
        var v = _item.elm.val();
        var d = new Date(v.toString());
        return d !== undefined&&d!='Invalid Date';
    }
}
//#endregion

//#region Ajax异步验证
function AjaxChecker(_editor,_actionUrl,_checkingInfo) {
    var editor, url, checkingInfo;
    if (!ObjHelper.IsElement(_editor) & !_editor instanceof Controller) {
        return undefined;
    }
    editor = _editor;
    url = _actionUrl;
    checkingInfo = _checkingInfo;

    var instance = this;
    function OnCheckEnd(rtn) {
        if (rtn.IsPositive) {
            //TODO:显示验证成功
            instance.IsChecking = false;
            instance.Pass = true;
            instance.vf_OnPass(rtn.Data);
        }
        else {
            //TODO:显示导致严重失败的原因
            instance.IsChecking = false;
            instance.Pass = false;
            instance.vf_OnError(rtn.Data);
        }
    };

    this.IsChecking = true;
    this.Pass = false;

    this.vf_OnPass = function (_passInfo) {
        /// <summary>
        /// 默认验证通过的提示方法
        /// </summary>
        /// <param name="_passInfo"></param>
    };

    this.vf_OnError = function (_errInfo) {
        /// <summary>
        /// 默认验证不通过时的处理方法
        /// </summary>
        /// <param name="_errInfo"></param>
    };

    this.Check = function () {
        //调用后台方法验证编辑控件的值是否合法
        $.getJSON(url, editor.val(), OnCheckEnd);
    };

    this.Dispose = function () {
        ObjHelper.DisposeObj(instance);
        instance = null;
    };

    return this;
}
//#endregion

//#region 弹出式菜单
function PopMenu(_opt) {
	/// <summary>
	/// 动态弹出式菜单
	/// </summary>
    /// <returns type=""></returns>
    Action.call(this);
    var instance = this;
    instance.menu = null; //菜单内容
    instance.evSlcMenu = null; //菜单内容控件触发选择值变化的事件
    instance.viewer = null; //负责展示菜单中选择的结果
    instance.fnViewSetter = null; //负责设置数据呈现控件的值
    instance.isLayoutNeed = true;
    instance.active = false;
    instance.clickHandled = false;
    instance.tmp = document.createDocumentFragment;

    this.Option = $.extend({}, PopMenuOption, _opt);

    function setMenu(_uiElm,_ev) {
        //TODO:设置菜单内容控件
        unsetMenu();
        instance.menu = _uiElm;
        instance.isLayoutNeed = true;
        _uiElm.dom(instance.tmp).addClass(instance.Option.StyleForMenu);
        _uiElm.on("click", onMenuClick);
        if (_ev) {
            _uiElm.on(_ev, onMenuSelected);
            instance.evSlcMenu = _ev;
        }
    };
    function unsetMenu() {
        if (instance.menu) {
            instance.menu.off("click", onMenuClick);
            if (instance.evSlcMenu) {
                instance.menu.off(instance.evSlcMenu, onMenuSelected);
                instance.evSlcMenu = null;
            }
        }
    };
    function setViewer(_uiElm,_fnSet) {
        //TODO:设置呈现菜单选择结果的控件
        if (instance.active===true) {
            hideMenu();
        }
        unsetViewer();
        instance.isLayoutNeed = true;
        instance.viewer = _uiElm;
        instance.fnViewSetter =ObjHelper.IsFunc(_fnSet)?_fnSet:PopMenuOption.FuncSetViewer;
        _uiElm.on("click", onViewerClick);
        KeybordHelper.on(_uiElm, "*", onViewerInput);
    };
    function unsetViewer() {
        if (instance.viewer) {
            instance.Fire("viewerUnseted");
            instance.viewer.off("click", onViewerClick);
            instance.fnViewSetter = null;
            KeybordHelper.off(instance.viewer, "*", onViewerInput);
            instance.viewer = null;
        };
    };
    function onBodyClick(ev) {
        if (instance.clickHandled === true) {
            instance.clickHandled = false;
            return;
        }
        instance.active = false;
        instance.clickHandled = true;
        hideMenu();
    };
    function onMenuClick(ev) {
        if (instance.active === true) {
            instance.clickHandled = true;
            if (instance.Option.AutoHide == true) {
                instance.hide();
            }
        };
    };
    function onMenuSelected(ev) {
        if (instance.fnViewSetter) {
            instance.fnViewSetter.call(this, instance.viewer, ev);
            if (instance.Option.AutoHide == true) {
                instance.hide();
            }
        }
    };
    function onViewerClick(ev) {
        if (instance.active === false) {
            showMenu();
            instance.active = true;
            instance.clickHandled = true;
        };
    };
    function onViewerInput(ev) {
        if (instance.active === false) {
            instance.active = true;
            showMenu();
        }
    };
    function showMenu() {
        if (instance.isLayoutNeed === true) {
            instance.isLayoutNeed = false;
            if (instance.Option.WidthMode === 'FitToViewer') {
                instance.menu.dom().css('width', instance.viewer.dom().outerWidth() + 'px');
            }
            else if (instance.Option.WidthMode === 'FitToContent') {
                instance.menu.dom().css('minWidth', instance.viewer.dom().outerWidth() + 'px');
            }
        }
        LayoutHelper.PosToBody(instance.viewer.dom(), instance.menu.dom(), "down-left", instance.Option.MenuOffset);
        instance.viewer.focus();
        instance.menu.show().dom($('body')).addClass('fladeInUp');

        //计算菜单高度是否超出view控件下方的可视空间
        var maxH = $('body').outerHeight() - instance.viewer.dom().offset().top - instance.viewer.dom().outerHeight() - 20;
        var mh = instance.menu.dom().outerHeight(true);
        instance.menu.dom().css('maxHeight', maxH-20);
        if (mh > maxH) {
            //如果菜单内容超出当前body可视区域，需让列表控件显示滚动条
            if (instance.menu instanceof List) {
                instance.menu.Scroller(true);
            }
        }
        instance.Fire('show');
    };
    function hideMenu() {
        instance.menu.hide().removeClass('fladeInUp').dom(instance.tmp);
        instance.Fire('hide');
    };

    this.Menu = function (_controller,_event) {
    	/// <summary>
    	/// 获取或设置作为弹出菜单的控件或JQueryDOM对象
    	/// </summary>
        /// <param name="_controller" type="Controller or JQueryDOM"></param>
        /// <param name="_event" type="string'>菜单控件触发设置Viewer值的事件类型</param>
        if (ObjHelper.IsEmpty(_controller)) {
            return instance.menu;
        }
        setMenu(_controller,_event);
        return instance;
    };

    this.Viewer = function (_controller,_fnSetValue) {
        /// <summary>
        /// 获取或设置用于展示菜单选择结果的控件或JQueryDOM对象
        /// </summary>
        /// <param name="_controller" type="Controller or JQueryDOM"></param>
        /// <param name="_fnSetValue" type="Function">设置数据呈现控件值的方法，当菜单项被选择后调用[若不提供，使用内置的标准方法回填]</param>
        if (ObjHelper.IsEmpty(_controller)) {
            return instance.viewer;
        }
        setViewer(_controller,_fnSetValue);
        return instance;
    };

    this.Dispose = function () {
        unsetMenu();
        unsetViewer();
        instance.fnViewSetter = null;
        $("body").off("click", onBodyClick);
        ObjHelper.DisposeObj(instance);
    };

    this.hide = function () {
        instance.active = false;
        hideMenu();
    };

    this.show = function () {
        if (instance.active === false) {
            instance.active = true;
            instance.clickHandled = true;
            showMenu();
        };
    };

    $('body').on("click", onBodyClick);
    
    this.constructor = PopMenu;
    return this;
}
PopMenu.prototype = Action.prototype;

var PopMenuOption={
    StyleForMenu: 'PopMenu',
    AutoHide:true,
    Filter:false, //是否对菜单项进行过滤【需设置Filter子成员】
    WidthMode: 'FitToViewer', //宽度控制方式：FitToViewer-与目标控件一致，FitToContent-由内容自己决定
    MenuOffset: { top: 0, left: 0 },
    FuncSetViewer: function (viewer, ev) {
        try{
            viewer.val(ev.Data);
        }
        catch(ex){

        }
    }
}
//#endregion

//#region 实时简单字段编辑功能
function FieldEditor() {
    Action.call(this);
    var instance = this;
    instance.valEditor = null;
    instance.state = 'editing';

    function onEditBlur() {
        var v = instance.valEditor.val();
        if (instance.$tg&&instance.$tg.val) {
            instance.$tg.val(v);
            if (instance.ValueSetter) {
                instance.ValueSetter(v);
            }
        }
        instance.valEditor.hide();
        instance.Dispose();
    };

    this.Editor = function (_controller) {
        /// <summary>
        /// 获取或设置当前编辑辅助器所关联的值编辑控件
        /// </summary>
        /// <param name="_controller"></param>
        if(ObjHelper.IsEmpty(_controller)){
            return instance.valEditor;
        }
        else if (ObjHelper.IsFunc(_controller.val)) {
            instance.valEditor = _controller.css('position','absolute');
            return this;
        }
        else {
            console.log('编辑辅助类只能绑定具有 val方法的对象');
            return this;
        }
    };

    this.Active = function (_targetElm,_valSetter) {
        if (ObjHelper.IsEmpty(_targetElm)) {
            return this;
        }
        else if (instance.valEditor) {
            instance.$tg = _targetElm;
            var pos = instance.$tg.offset();
            var w = instance.$tg.outerWidth();
            var h = instance.$tg.outerHeight();

            instance.valEditor.appendTo($('body')).show().offset(pos).width(w).height(h).focus().select();
            instance.valEditor.on('blur', onEditBlur);
            if (ObjHelper.IsFunc(_valSetter)) {
                instance.ValueSetter = _valSetter;
            }
        }
        else {
            return this;
        }
    };

    this.Dispose = function () {
        if (instance.IsDisposed) {
            return;
        }
        else {
            instance.IsDisposed = true;
            instance.ValueSetter = null;
            instance.valEditor = null;
            instance.$tg = null;
            ObjHelper.DisposeObj(instance);
            return;
        }
    };

    FieldEditor.constructor = FieldEditor;
    return this;
};

//#endregion